package com.web_bloks.mvc.client;

import java.util.LinkedHashMap;

import com.google.gwt.core.client.GWT;

/**
 * 
 * @author Jean-Lou Dupont
 *
 */
public class Controller implements IController {

	/** 
	 * Singleton instance
	 */
	protected static Controller instance;

	/**
	 * Mapping of Notification names to Command Class references
	 */
	protected LinkedHashMap<String, ICommand> commandMap;

	/**
	 * Local reference to View
	 */
	protected View view;

	/**
	 * Constructor.
	 */
	protected Controller( )	{
		instance = this;
		this.commandMap = new LinkedHashMap<String, ICommand>();
		initializeController();
	}

	/**
	 * Initialize the Singleton <code>Controller</code> instance.
	 */
	protected void initializeController( ) {
		this.view = View.getInstance();
	}

	/**
	 * <code>Controller</code> Singleton Factory method.
	 * 
	 * @return the Singleton instance of <code>Controller</code>
	 */
	public static Controller getInstance( ) {
		if (instance == null) {
			instance = GWT.create( Controller.class );
		}
		return instance;
	}

	/**
	 * If an <code>ICommand</code> has previously been registered to handle a
	 * the given <code>INotification</code>, then it is executed.
	 * 
	 * @param note
	 *            an <code>INotification</code>
	 */
	public void executeCommand( INotification note ) {
		
		ICommand commandClassInstance = this.commandMap.get( note.getNotificationName() );
		if (commandClassInstance == null) {
			return;
		}
		try {
			//No reflexion in either the following two ways:
			//ICommand commandInstance = (ICommand) commandClassRef.newInstance();
			//ICommand commandInstance = (ICommand) GWT.create( commandClassRef.getClass() );
			commandClassInstance.execute( note );
		} catch (Exception e) {
		}
	}

	/**
	 * Register a particular <code>ICommand</code> class as the handler for a
	 * particular <code>INotification</code>.
	 * 
	 * @param notificationName
	 * @param commandClassInstance
	 */
	public void registerCommand( INotification note, ICommand commandClassInstance ) {
		
		// already registered?
		if (null != this.commandMap.put( note.getNotificationName(), commandClassInstance )) 
			return;
		
		// register the command with the view since it already has
		// all the logic to dispatch to Observers
		this.view.registerObserver( note.getNotificationName(), new Observer( new IMethod()
		{
			public void onNotification( INotification notification )
			{
				executeCommand( notification );
			}
		}, this ) );
	}

	/**
	 * Remove a previously registered <code>ICommand</code> to
	 * <code>INotification</code> mapping.
	 * 
	 * @param notificationName
	 *            the name of the <code>INotification</code> to remove the
	 *            <code>ICommand</code> mapping for
	 */
	public void removeCommand( INotification note )
	{
		this.commandMap.remove( note.getNotificationName() );
	}


}//END
